home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
3D GFX
/
3D GFX.iso
/
amiutils
/
m_p
/
photocdaga
/
src
/
ppm2aga
/
ppm2ilbm.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-12-30
|
31KB
|
999 lines
/* ppm2ilbm module */
/* written by Gⁿnther R÷hrich */
/* this is version 1.5 */
/* this code is tested with Aztec C 5.2a and GNU C 2.5.8 */
/* NOTE: you will need the newiff V37 or higher package */
/* (V37 is available on Fish-disk 705) */
#include <clib/exec_protos.h>
#include <libraries/iffparse.h>
#include <dos/dos.h>
#include <iffp/ilbmapp.h>
#include <iffp/packer.h>
#include <stdio.h>
#include <graphics/modeid.h>
#include "ppm2AGA.h"
#ifndef __GNUC__
#include <pragmas/exec_pragmas.h>
#include <pragmas/iffparse_pragmas.h>
#endif
/* needed when compiling with newiff V37 package */
/* (not needed with V39 or higher) */
#ifndef BMHDF_CMAPOK
#define BMHDF_CMAPOK (1 << 7)
#endif
#define random rand
/* externals used by this module */
extern int AbortCheck(void);
extern void PLProgress(ULONG Value, ULONG MaxValue);
extern volatile unsigned short MaxError, MaxErrorPos;
extern void EncodeHAM(UBYTE *yorig, UBYTE *yham, char *ColorTable,
short NumColors, short xsize);
extern int MapColorASM(colorhist_vector colormap, pixval r1, pixval g1, pixval b1,
int NumColors);
extern int ExactColor;
extern int GfxEnable;
extern int VGAenable;
extern int jpegAGA;
extern char *ILBMfile;
extern char *BaseName;
extern ULONG SMR;
extern ULONG SMR_DisplayID;
/* definitions for the display routines */
extern int InitDisplay(int cols, int rows, ULONG Mode, int NumPlanes);
extern void SetDisplayColor(int ColorNumber, UBYTE r, UBYTE g, UBYTE b);
extern void DisplayRow(char *array, int cols, int row);
extern void CloseDisplay(void);
/* globals defined in this module */
#ifdef DEBUG_ASM
int MapColor(colorhist_vector colormap, pixval r1, pixval g1, pixval b1,
int NumColors);
#endif
unsigned short Mult_Table[2*256];
unsigned long Mult_Table32[2*256];
jmp_buf ErrorEnv;
int cols, rows, rowcnt;
pixel **pixels;
pixel *pixrow;
pixval maxval;
int ppmformat;
char ColorTable[64*3] = {0};
int ColorRegMax;
unsigned short ConvertMode;
char *ColorCache; /* a 256K cache for EncodeHAM() */
/* these are needed by Floyd-Steinberg-routines */
long *thisrerr;
long *nextrerr;
long *thisgerr;
long *nextgerr;
long *thisberr;
long *nextberr;
extern int floyd;
int fs_direction = 1;
int Convert4096;
int Convert262144;
#define FS_SCALE 1024
/* locals defined in this module */
static FILE *fppm;
static FILE *ColorMapFile;
static struct IFFHandle *iff;
static struct ILBMInfo ilbm;
static int error;
static LONG IFFError;
static unsigned char *coded_rowbuf;
static unsigned char *hamarray;
static int returnvalue;
static void ppmCleanUp(void);
static int readall;
static colorhist_vector chv, colormap;
static BYTE *CompressBuffer;
static void encode_row(UBYTE *row, int cols, int nPlanes);
static int ColorShift, NumColors;
static gray *pgmrow;
static int lumcompare(colorhist_vector ch1, colorhist_vector ch2)
{
return (int)((double)PPM_LUMIN(ch1->color) - (double)PPM_LUMIN(ch2->color));
}
int ppm2ilbm(char *PPMfile, ULONG Mode, int NumPlanes, ULONG MaxMem)
{
int i, colors;
pixel *pP;
unsigned short AbsMaxError = 0;
unsigned short MaxErrorXPos = 0;
unsigned short MaxErrorYPos = 0;
/* initialize everything */
/* this is needed because we may call this function */
/* multiple times */
returnvalue = 0;
fppm = NULL;
ColorMapFile = NULL;
readall = 0;
pixrow = NULL;
pixels = NULL;
hamarray = NULL; coded_rowbuf = NULL; ColorCache=NULL;
memset(&ilbm, 0, sizeof(struct ILBMInfo));
chv = NULL;
colormap = NULL;
CompressBuffer = NULL;
pgmrow = NULL;
/* multiplication table is needed by assembler subroutines */
for(i=-255; i<256; i++)
{
Mult_Table[i+255] = i*i;
Mult_Table32[i+255] = i*i;
}
/* if we encounter an error we longjmp() to this location */
/* the ppmCleanUp() function will free all resources allocated */
/* in this module */
error = setjmp(ErrorEnv);
if(error != 0)
{
ppmCleanUp();
return error;
}
/* try to open the ppm file */
fppm = fopen(PPMfile, "r");
if(!fppm) pm_error("Could not open file %s\n", PPMfile);
/* read the header of the ppm file */
ppm_readppminit(fppm, &cols, &rows, &maxval, &ppmformat);
#ifdef DEBUG
pm_message("Cols: %d, Rows: %d, MaxVal: %d, Format: %d\n",
cols, rows, maxval, ppmformat);
#else
pm_message("Cols: %d, Rows: %d, MaxVal: %d\n", cols, rows, maxval);
#endif
/* Initialize Floyd-Steinberg error vectors. */
thisrerr = (long*) pm_allocrow( cols + 2, sizeof(long) );
nextrerr = (long*) pm_allocrow( cols + 2, sizeof(long) );
thisgerr = (long*) pm_allocrow( cols + 2, sizeof(long) );
nextgerr = (long*) pm_allocrow( cols + 2, sizeof(long) );
thisberr = (long*) pm_allocrow( cols + 2, sizeof(long) );
nextberr = (long*) pm_allocrow( cols + 2, sizeof(long) );
/* srandom( (int) ( time( 0 ) ^ getpid(0) ) ); */
for ( i = 0; i < cols + 2; ++i )
{
thisrerr[i] = random( ) % ( FS_SCALE * 2 ) - FS_SCALE;
thisgerr[i] = random( ) % ( FS_SCALE * 2 ) - FS_SCALE;
thisberr[i] = random( ) % ( FS_SCALE * 2 ) - FS_SCALE;
/* (random errors in [-1 .. 1]) */
}
/* try to open the output file */
if(!jpegAGA)
{
if(!(ilbm.ParseInfo.iff = AllocIFF()))
pm_error("Could not do AllocIFF()");
iff = ilbm.ParseInfo.iff;
IFFError = openifile((struct ParseInfo *)&ilbm, (UBYTE *)ILBMfile, IFFF_WRITE);
if(IFFError) pm_error(""); /* openifile() will print error messages... */
}
if(Mode == HAM8 || Mode == HAM6 || Mode == COLORMAP)
{
int Clustering;
if(Mode == HAM8)
{
NumColors = NumPlanes;
ColorRegMax = 63;
ColorShift = 2; /* we only have 256K colors */
NumPlanes = 8;
ConvertMode = 1; /* Needed by EncodeHAM() */
Clustering = 0;
Convert4096 = 0; /* No 4096-FS conversion */
if(floyd) Convert262144 = 1; /* 262144 conversion */
}
else if(Mode == HAM6)
{
NumColors = NumPlanes;
ColorRegMax = 15;
ColorShift = 4; /* converting to 4096 colors will be done by FS dithering */
NumPlanes = 6;
ConvertMode = 0; /* Needed by EncodeHAM() */
Clustering = 0;
if(floyd)
Convert4096 = 1; /* Do 4096-FS conversion */
Convert262144 = 0;
}
else /* COLORMAP */
{
NumColors = 1 << NumPlanes;
ColorRegMax = 255;
ColorShift = 0; /* we will handle full 16M colors */
if(ppmformat == PGM_FORMAT || ppmformat == RPGM_FORMAT || ExactColor == 1)
{
Clustering = 0;
}
else
{
Clustering = 2;
}
Convert4096 = 0; /* No 4096-FS conversion */
Convert262144 = 0;
}
if( cols*rows*3 <= (int)MaxMem)
{
/* read the complete picture into memory */
int row;
readall = 1;
pm_message("Reading complete picture into memory...\n");
pixels = ppm_allocarray(cols, rows);
for(row = 0; row < rows; ++row)
{
if(AbortCheck()) pm_error("^C\n");
ppm_readppmrow(fppm, pixels[row], cols, maxval, ppmformat);
if(maxval != ColorRegMax)
{
if(maxval == 255)
{
for(i=0, pP=pixels[row]; i < cols; ++i, ++pP)
{
pP->r = pP->r >> ColorShift;
pP->g = pP->g >> ColorShift;
pP->b = pP->b >> ColorShift;
}
}
else
{
for(i=0, pP=pixels[row]; i < cols; ++i, ++pP)
PPM_DEPTH(*pP, *pP, maxval, ColorRegMax);
}
}
}
}
else
{
rowcnt = 0;
if(!(pixrow = ppm_allocrow(cols)))
pm_error("Out of memory.\n");
}
/* allocate enough room for one row of chunky HAM pixels */
/* (this array will also be used for colormap conversion) */
if(!(hamarray = malloc(RowBits(cols))))
pm_error("Out of memory.\n");
/* we only have to clear the space between cols and RowBits(cols) */
/* hamarray will be larger in most cases because of special alignment*/
for(i = cols; i < RowBits(cols); i++) hamarray[i] = 0;
pm_message("Computing colormap...\n");
/* now we make a histogram of the picture... */
/* if we increase Clustering we will find less colors */
/* we allow a maximum of 10000 colors */
/* ColorShift is the shift needed for HAM encoding */
for(i=Clustering; i<5; i++)
{
if((chv = ppm_fcomputecolorhist(fppm, cols, rows, 10000, &colors, ColorShift, i)))
break;
if(AbortCheck()) pm_error("^C\n");
pm_message("Could not compute colormap, trying again...\n");
rowcnt=0;
if(!readall)
{
rewind(fppm); /* re-initialise the ppm pointers for reading again */
ppm_readppminit(fppm, &cols, &rows, &maxval, &ppmformat);
}
}
pm_message("Found %d colors.\n", colors);
/* now we try to find a suitable colormap... */
colormap = mediancut(chv, colors, rows*cols, ColorRegMax, NumColors);
ppm_freecolorhist(chv); /* we don't need the histogram any more */
chv = NULL;
/* sort the colors in ascending luminance order... */
/* (the first color will be the background color) */
if(NumColors < colors)
{
qsort((char *)colormap, NumColors, sizeof(struct colorhist_item), lumcompare);
}
else
{
qsort((char *)colormap, colors, sizeof(struct colorhist_item), lumcompare);
}
if(!jpegAGA)
{
/* the CompressBuffer is needed by the cmpByteRun1 compressor */
if(!(CompressBuffer = malloc(MaxPackedSize(RowBytes(cols)))))
pm_error("Out of memory allocating the compress buffer.\n");
/* the ColorCache is needed by EncodeHAM() for higher speed */
/* (for HAM6 encoding only 4097 bytes are needed...) */
if(!(ColorCache = malloc(262145)))
pm_error("Out of memory allocating the color cache.\n");
/* the coded_rowbuf is needed by the IFF encoder */
if(!(coded_rowbuf = (unsigned char *)malloc(RowBytes(cols))))
pm_error("Out of memory allocating coded_rowbuf.\n");
for(i=RowBytes(cols)-1; i>=0; i--) coded_rowbuf[i]=0;
/* write the FORM chunk */
IFFError = PushChunk(iff, ID_ILBM, ID_FORM, IFFSIZE_UNKNOWN);
if(IFFError) pm_error("Error writing FORM chunk.\n");
/* initialize the BMHD chunk */
ilbm.Bmhd.w = cols;
ilbm.Bmhd.h = rows; /* Width, height in pixels */
ilbm.Bmhd.x = 0;
ilbm.Bmhd.y = 0; /* x, y position for this bitmap */
ilbm.Bmhd.nPlanes = NumPlanes; /* # of planes (not including mask) */
ilbm.Bmhd.masking = mskNone;
ilbm.Bmhd.compression = cmpByteRun1;
ilbm.Bmhd.flags = BMHDF_CMAPOK; /* CMAP has 8 significant bits */
ilbm.Bmhd.transparentColor = 0;
ilbm.Bmhd.xAspect = cols;
ilbm.Bmhd.yAspect = rows; /* xAspect, yAspect */
ilbm.Bmhd.pageWidth = cols;
ilbm.Bmhd.pageHeight = rows; /* pageWidth, pageHeight */
/* write the BMHD chunk */
IFFError = putbmhd(iff, &ilbm.Bmhd);
if(IFFError) pm_error("Error writing BMHD chunk.\n");
if(GfxEnable) InitDisplay(cols, rows, Mode, NumPlanes);
}
if(Mode == HAM8 || Mode == HAM6)
{
/* fill in the ColorTable in B R G order */
/* (this is better for HAM encoding) */
for(i=0; i<NumColors; i++)
{
ColorTable[i*3] = PPM_GETB(colormap[i].color);
ColorTable[i*3+1] = PPM_GETR(colormap[i].color);
ColorTable[i*3+2] = PPM_GETG(colormap[i].color);
if(!jpegAGA)
{
if(ColorShift == 4)
SetDisplayColor(i, (PPM_GETR(colormap[i].color) << ColorShift) |
PPM_GETR(colormap[i].color),
(PPM_GETG(colormap[i].color) << ColorShift) |
PPM_GETG(colormap[i].color),
(PPM_GETB(colormap[i].color) << ColorShift) |
PPM_GETB(colormap[i].color));
else
SetDisplayColor(i, (PPM_GETR(colormap[i].color) << ColorShift),
(PPM_GETG(colormap[i].color) << ColorShift),
(PPM_GETB(colormap[i].color) << ColorShift));
}
}
free(colormap); /* we don't need the colormap any more */
colormap = NULL;
if(jpegAGA)
{
char *MapDir;
unsigned short MagicNumber = 0x1203; /* guess what this means! */
int Reserved=0;
unsigned char color;
MapDir = getenv("MAPDIR");
ColorMapFile = fopen(ILBMfile, "w");
if(!ColorMapFile && !BaseName)
{
if(MapDir)
if(strlen(MapDir) != 0)
{
char *MapDirName;
int pos,i;
MapDirName = malloc(strlen(MapDir)+strlen(ILBMfile)+5); /* worst case */
if(!MapDirName) pm_error("Out of memory.\n");
strcpy(MapDirName, MapDir);
i = strlen(MapDirName);
if(MapDirName[i-1] != '/' && MapDirName[i-1] != ':')
{
strcat(MapDirName, "/");
i++;
}
i = strlen(ILBMfile);
while(i > 0 && ILBMfile[i-1] != '/' && ILBMfile[i-1] != ':') i--;
strcat(MapDirName, &ILBMfile[i]);
ColorMapFile = fopen(MapDirName, "w");
if(ColorMapFile) pm_message("Writing mapfile: %s\n", MapDirName);
}
}
else if(!ColorMapFile && BaseName && MapDir)
if(strlen(MapDir) != 0)
{
char *NewName;
int i;
NewName = malloc(strlen(MapDir)+strlen(BaseName)+strlen(ILBMfile)); /* worst case */
if(!NewName) pm_error("Out of memory.\n");
strcpy(NewName, MapDir);
i=strlen(NewName);
if(NewName[i-1] != '/' && NewName[i-1] != ':')
{
strcat(NewName, "/");
i++;
}
strcat(NewName, BaseName);
i=strlen(ILBMfile);
while(i > 0 && ILBMfile[i-1] != '/' && ILBMfile[i-1] != ':') i--;
if(strlen(ILBMfile) > i+3)
{
strcat(NewName, &ILBMfile[i+3]);
i = strlen(NewName) - 4;
if(i < 1) pm_error("Wrong mapfile name.\n");
while(i > 0 && NewName[i-1] != '.') i--;
if(NewName[i-1] == '.')
{
strcpy(&NewName[i], "map");
printf("%s\n", NewName);
ColorMapFile = fopen(NewName, "w");
}
}
free(NewName);
}
if(!ColorMapFile) pm_error("Could not open color map file for jpegAGA.\n");
if(fwrite(&MagicNumber, 2, 1, ColorMapFile) != 1) pm_error("Write error.\n");
if(fwrite(&Reserved, 4, 1, ColorMapFile) != 1) pm_error("Write error.\n");
if(fwrite(ColorTable, 64*3, 1, ColorMapFile) != 1) pm_error("Write error.\n");
pm_message("Colormap file for jpegAGA/PhotoCDAGA created.\n");
ppmCleanUp();
return 0;
}
memset(ColorCache, 0, 262145); /* clear the color cache */
do
{
int y;
rowcnt=0;
/* if we don't need an additional color the color cache */
/* will remain valid and should not be cleared */
memset(ColorCache, 0, 262145); /* clear the color cache */
if(!readall)
{
rewind(fppm);
ppm_readppminit(fppm, &cols, &rows, &maxval, &ppmformat);
}
/* if we have all colors we can write the CMAP chunk */
if(NumColors == ColorRegMax+1)
{
IFFError = PushChunk(iff, 0, ID_CMAP, (ColorRegMax+1)*3);
if(IFFError) pm_error("Error writing CMAP header.\n");
for( i = 0; i <= ColorRegMax; i++)
{
ColorRegister cmapReg;
if(ColorShift == 4) /* HAM6 */
{
cmapReg.red = (ColorTable[i*3+1] << ColorShift)
| ColorTable[i*3+1]; /* red */
cmapReg.green = (ColorTable[i*3+2] << ColorShift)
| ColorTable[i*3+2]; /* green */
cmapReg.blue = (ColorTable[i*3] << ColorShift)
| ColorTable[i*3]; /* blue */
}
else /* HAM8 */
{
cmapReg.red = ColorTable[i*3+1] << ColorShift; /* red */
cmapReg.green = ColorTable[i*3+2] << ColorShift; /* green */
cmapReg.blue = ColorTable[i*3] << ColorShift; /* blue */
}
IFFError = WriteChunkBytes(iff, (UBYTE *)&cmapReg, 3);
if(IFFError!=3) pm_error("Error writing CMAP chunk.\n");
}
IFFError = PopChunk(iff); /* close CMAP */
if(IFFError) pm_error("Error closing CMAP.\n");
/* write the CAMG chunk */
if(SMR)
{
ilbm.camg = SMR_DisplayID;
}
else
{
if(VGAenable)
{
if(cols > 370 || rows > 260)
{
ilbm.camg = VGAPRODUCTHAM_KEY;
}
else
{
ilbm.camg = VGALORESHAMDBL_KEY;
}
}
else
{
ilbm.camg = HAM;
if(cols > 370) ilbm.camg = ilbm.camg | HIRES;
if(rows > 280) ilbm.camg = ilbm.camg | LACE;
}
}
IFFError = putcamg(iff, &ilbm.camg);
if(IFFError) pm_error("Error writing CAMG chunk.\n");
/* start with the BODY chunk */
IFFError = PushChunk(iff, 0, ID_BODY, IFFSIZE_UNKNOWN);
if(IFFError) pm_error("Error writing BODY header.\n");
}
/* set a dummy value for AbsMaxError */
/* it will contain the maximum error for the complete picture */
AbsMaxError=0;
for(y=0; y<rows; y++)
{
pixel *nextrow;
MaxError = 0;
nextrow = next_pixrow(fppm, y, ColorShift);
if(AbortCheck()) pm_error("^C\n");
EncodeHAM(nextrow, hamarray, ColorTable, NumColors*3, (short)cols);
/* remember the color of the pixel with the maximum error */
/* even if MaxError == 0 we will get a valid entry in the */
/* colormap but it will not be used by the picture */
if(MaxError > AbsMaxError)
{
MaxErrorXPos = MaxErrorPos;
MaxErrorYPos = y;
AbsMaxError = MaxError;
/* use the color of the pixel with the maximum error as */
/* a ColorTable entry */
/* we will have to recompute the picture if we want to */
/* use the additional color */
if(NumColors <= ColorRegMax)
{
ColorTable[NumColors*3] = PPM_GETB(pixrow[MaxErrorXPos]);
ColorTable[NumColors*3+1] = PPM_GETR(pixrow[MaxErrorXPos]);
ColorTable[NumColors*3+2] = PPM_GETG(pixrow[MaxErrorXPos]);
}
}
/* if all colors are set we can write our row to the BODY chunk */
if(NumColors == ColorRegMax+1)
{
encode_row(hamarray, cols, NumPlanes);
}
DisplayRow(hamarray, cols, y);
}
/* this is only for debugging purposes */
if(NumColors <= ColorRegMax)
{
#ifdef DEBUG
pm_message("Max Error: %hd ", AbsMaxError);
#endif
if(AbsMaxError == 0)
{
printf("\n");
}
else
{
#ifdef DEBUG
pm_message("Color %hd, XPos: %hd, YPos: %hd\n", NumColors, MaxErrorXPos, MaxErrorYPos);
#endif
}
}
SetDisplayColor(NumColors, ColorTable[NumColors*3+1] << ColorShift,
ColorTable[NumColors*3+2] << ColorShift,
ColorTable[NumColors*3] << ColorShift);
NumColors = NumColors + 1;
/* finish if we have set all colors */
} while(NumColors <= ColorRegMax+1);
#ifdef DEBUG
pm_message("Max Error: %hd, XOffset: %hd YOffset: %hd\n",
AbsMaxError, MaxErrorXPos, MaxErrorYPos);
pm_message("Colortable: ");
for(i=0; i<=ColorRegMax; i++)
{
pm_message("%hd,%hd,%hd ",ColorTable[i*3],
ColorTable[i*3+1],ColorTable[i*3+2]);
}
pm_message("\n");
#endif
/* close the BODY chunk */
IFFError = PopChunk(iff);
if(IFFError) pm_message("Error closing the BODY chunk.\n");
}
else if(Mode == COLORMAP)
{
/* if floyd is nonzero we will use Floyd-Steinberg dithering */
int row, fs_direction;
register int col, limitcol, ind;
register pixel *pP;
register long sg, sr, sb, err;
long *temperr;
/*
** map the colors in the image to their closest match in the
** new colormap, and write 'em out.
*/
pm_message( "Mapping image to new colors...\n" );
/* write the CMAP chunk */
IFFError = PushChunk(iff, 0, ID_CMAP, NumColors*3);
if(IFFError) pm_error("Error writing CMAP header.\n");
for( i = 0; i < NumColors; i++)
{
ColorRegister cmapReg;
cmapReg.red = PPM_GETR( colormap[i].color ); /* red */
cmapReg.green = PPM_GETG( colormap[i].color ); /* green */
cmapReg.blue = PPM_GETB( colormap[i].color ); /* blue */
SetDisplayColor(i, cmapReg.red, cmapReg.green, cmapReg.blue);
IFFError = WriteChunkBytes(iff, (UBYTE *)&cmapReg, 3);
if(IFFError!=3) pm_error("Error writing CMAP chunk.\n");
}
IFFError = PopChunk(iff); /* close CMAP */
if(IFFError) pm_error("Error closing CMAP.\n");
/* write the CAMG chunk */
if(SMR)
{
ilbm.camg = SMR_DisplayID;
}
else
{
ilbm.camg = 0;
if(VGAenable)
{
if(cols > 370 || rows > 260)
ilbm.camg = VGAPRODUCT_KEY;
else
ilbm.camg = VGALORESDBL_KEY;
}
else
{
if(cols > 370) ilbm.camg = ilbm.camg | HIRES;
if(rows > 280) ilbm.camg = ilbm.camg | LACE;
}
}
IFFError = putcamg(iff, &ilbm.camg);
if(IFFError) pm_error("Error writing CAMG chunk.\n");
/* start with the BODY chunk */
IFFError = PushChunk(iff, 0, ID_BODY, IFFSIZE_UNKNOWN);
if(IFFError) pm_error("Error writing BODY header.\n");
rowcnt=0;
if(!readall)
{
rewind(fppm);
ppm_readppminit(fppm, &cols, &rows, &maxval, &ppmformat);
}
if ( floyd )
{
fs_direction = 1;
}
for ( row = 0; row < rows; ++row )
{
/* PLProgress(row, rows); */
if(AbortCheck()) pm_error("^C\n");
if ( floyd )
for ( col = 0; col < cols + 2; ++col )
nextrerr[col] = nextgerr[col] = nextberr[col] = 0;
if ( ( ! floyd ) || fs_direction )
{
col = 0;
limitcol = cols;
/* pP = pixels[row]; */
pP = next_pixrow(fppm, row, ColorShift);
}
else
{
col = cols - 1;
limitcol = -1;
/* pP = &(pixels[row][col]); */
pP = &(next_pixrow(fppm, row, ColorShift)[col]);
}
do
{
if ( floyd )
{
/* Use Floyd-Steinberg errors to adjust actual color. */
sr = PPM_GETR(*pP) + thisrerr[col + 1] / FS_SCALE;
sg = PPM_GETG(*pP) + thisgerr[col + 1] / FS_SCALE;
sb = PPM_GETB(*pP) + thisberr[col + 1] / FS_SCALE;
if ( sr < 0 ) sr = 0;
else if ( sr > maxval ) sr = maxval;
if ( sg < 0 ) sg = 0;
else if ( sg > maxval ) sg = maxval;
if ( sb < 0 ) sb = 0;
else if ( sb > maxval ) sb = maxval;
PPM_ASSIGN( *pP, sr, sg, sb );
}
/* use the assembler subroutine for the colormap search */
/* this will consume most of the CPU time */
ind = MapColorASM(colormap, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP),
NumColors);
/* compare the results of the ASM versus the C routine */
/* if they differ the ASM routine has a bug... */
/* (we don't need them because they are the same now) */
#ifdef DEBUG_ASM
if(ind != MapColor(colormap, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP),
NumColors))
pm_message("Diff: row %d col %d r %d g %d b %d\n", row,col,
(int)PPM_GETR(*pP), (int)PPM_GETG(*pP), (int)PPM_GETB(*pP));
#endif
if ( floyd )
{
/* Propagate Floyd-Steinberg error terms. */
if ( fs_direction )
{
err = ( sr - (long) PPM_GETR( colormap[ind].color ) ) * FS_SCALE;
thisrerr[col + 2] += ( err * 7 ) / 16;
nextrerr[col ] += ( err * 3 ) / 16;
nextrerr[col + 1] += ( err * 5 ) / 16;
nextrerr[col + 2] += ( err ) / 16;
err = ( sg - (long) PPM_GETG( colormap[ind].color ) ) * FS_SCALE;
thisgerr[col + 2] += ( err * 7 ) / 16;
nextgerr[col ] += ( err * 3 ) / 16;
nextgerr[col + 1] += ( err * 5 ) / 16;
nextgerr[col + 2] += ( err ) / 16;
err = ( sb - (long) PPM_GETB( colormap[ind].color ) ) * FS_SCALE;
thisberr[col + 2] += ( err * 7 ) / 16;
nextberr[col ] += ( err * 3 ) / 16;
nextberr[col + 1] += ( err * 5 ) / 16;
nextberr[col + 2] += ( err ) / 16;
}
else
{
err = ( sr - (long) PPM_GETR( colormap[ind].color ) ) * FS_SCALE;
thisrerr[col ] += ( err * 7 ) / 16;
nextrerr[col + 2] += ( err * 3 ) / 16;
nextrerr[col + 1] += ( err * 5 ) / 16;
nextrerr[col ] += ( err ) / 16;
err = ( sg - (long) PPM_GETG( colormap[ind].color ) ) * FS_SCALE;
thisgerr[col ] += ( err * 7 ) / 16;
nextgerr[col + 2] += ( err * 3 ) / 16;
nextgerr[col + 1] += ( err * 5 ) / 16;
nextgerr[col ] += ( err ) / 16;
err = ( sb - (long) PPM_GETB( colormap[ind].color ) ) * FS_SCALE;
thisberr[col ] += ( err * 7 ) / 16;
nextberr[col + 2] += ( err * 3 ) / 16;
nextberr[col + 1] += ( err * 5 ) / 16;
nextberr[col ] += ( err ) / 16;
}
}
/* *pP = colormap[ind].color; */
hamarray[col] = (unsigned char)ind;
if ( ( ! floyd ) || fs_direction )
{
++col;
++pP;
}
else
{
--col;
--pP;
}
}
while ( col != limitcol );
if ( floyd )
{
temperr = thisrerr;
thisrerr = nextrerr;
nextrerr = temperr;
temperr = thisgerr;
thisgerr = nextgerr;
nextgerr = temperr;
temperr = thisberr;
thisberr = nextberr;
nextberr = temperr;
fs_direction = ! fs_direction;
}
/* ppm_writeppmrow( stdout, pixels[row], cols, maxval, 0 ); */
/* write one row to the BODY chunk */
encode_row(hamarray, cols, NumPlanes);
DisplayRow(hamarray, cols, row);
}
IFFError = PopChunk(iff); /* close the BODY */
if(IFFError) pm_error("Error closing the BODY chunk.\n");
}
}
closeifile((struct ParseInfo *)&ilbm);
ppmCleanUp();
return 0;
}
/* free all resources used by this module */
void ppmCleanUp(void)
{
CloseDisplay();
if(colormap) free(colormap);
if(pgmrow) pgm_freerow(pgmrow);
if(coded_rowbuf) free(coded_rowbuf);
if(CompressBuffer) free(CompressBuffer);
if(ColorCache) free(ColorCache);
if(chv) free(chv);
if(hamarray) free(hamarray);
if(pixels)
{
ppm_freearray(pixels, rows);
}
else
{
if(pixrow) pbm_freerow(pixrow);
}
if(fppm) fclose(fppm);
if(jpegAGA)
{
if(ColorMapFile)
{
fclose(ColorMapFile);
ColorMapFile = NULL;
}
}
else
{
if(ilbm.ParseInfo.opened)
{
closeifile((struct ParseInfo *)&ilbm);
remove(ILBMfile);
}
if(ilbm.ParseInfo.iff) FreeIFF(ilbm.ParseInfo.iff);
}
}
/* convert one row from chunky to planar, compress it, */
/* and write it to the BODY chunk */
/* encode algorithm by Johan Widen (jw@jwdata.se) */
/* modified by Gⁿnther R÷hrich */
const unsigned char bit_mask[] = {1, 2, 4, 8, 16, 32, 64, 128};
static void
encode_row(UBYTE *row, int cols, int nPlanes)
{
register int plane, col;
int bytes;
LONG packedRowBytes;
BYTE *source;
BYTE *destination;
bytes = RowBytes(cols);
/* Encode and write raw bytes in plane-interleaved form. */
for( plane = 0; plane < nPlanes; plane++ )
{
int mask, cbit, wr;
unsigned char *cp;
UBYTE *rp;
mask = 1 << plane;
cbit = -1;
cp = coded_rowbuf-1;
rp = row;
for( col = 0; col < cols; col++, cbit--, rp++ )
{
if( cbit < 0 )
{
cbit = 7;
*++cp = 0;
}
if( *rp & mask )
*cp |= bit_mask[cbit];
}
/* wr = fwrite(coded_rowbuf, 1, bytes, stdout); */
/* compress the row */
source = coded_rowbuf;
destination = CompressBuffer;
packedRowBytes = packrow(&source, &destination, bytes);
/* write the compressed row to the BODY chunk */
IFFError = WriteChunkBytes(iff, CompressBuffer, packedRowBytes);
if(IFFError!=packedRowBytes) pm_error("Error writing BODY chunk.\n");
}
}
#ifdef DEBUG_ASM
/* this is the C version of the colormap search routine */
/* (it is now replaced by the ASM version) */
/* search colormap for closest match. */
int MapColor(colorhist_vector colormap, pixval r, pixval g, pixval b,
int newcolors)
{
int ind;
register int i, r1, g1, b1, r2, g2, b2;
register long dist, newdist;
r1 = r;
g1 = g;
b1 = b;
dist = 2000000000;
for ( i = 0; i < newcolors; ++i )
{
r2 = PPM_GETR( colormap[i].color );
g2 = PPM_GETG( colormap[i].color );
b2 = PPM_GETB( colormap[i].color );
newdist = ( r1 - r2 ) * ( r1 - r2 ) +
( g1 - g2 ) * ( g1 - g2 ) +
( b1 - b2 ) * ( b1 - b2 );
if ( newdist < dist )
{
ind = i;
dist = newdist;
}
}
return ind;
}
#endif